import wcwidth from "wcwidth";
import { AObject } from "./AObject";
import { RoutineUtility } from "./ARoutine";
import type { Agent } from "./Agent";
import { Character } from "./Character";
import { AVerb, VerbSpecification, parseNumber, type CommandConfig } from "./CommandParser";
import * as Debug from "./Debug";
import { ActionReportType, ContainerType, DirectionNames, RoutineResult, RoutineResultType, type ActionReportArguments, type ScheduledRoutine } from "./Definitions";
import { HistoryEntry, N, NH, Signifier, type SentenceContent } from "./NarrativeBase";
import { NLPError } from "./Selector";
import { U } from "./Util";
import { World, type ScheduledProcess, type TypedScheduledProcess } from "./WorldBase";

function disamb(ag: Agent, name: string | null, objs: AObject[]) {
    let str = name == null ? name + '\n' : '';
    for (let i = 0; i < objs.length; i++) {
        str += `[${i.toString().padStart(2, ' ')}] - ${objs[i].name.value}`;
        let p = objs[i].parentContainer;
        if (p != null && p instanceof AObject)
            str += `（在${p.name.value}${p.containerType == ContainerType.Surface ? '上' : '里'}）`;
        if (p == ag)
            str += ag.holdingItem == objs[i] ? '（你正在搬着它）' : '（在你的身上）';
        if (objs[i].parentPart != null)
            str += `（${objs[i].parentPart!.name.value}的一部分）`;
        str += '\n';
    }
    str += `\n（选择一个序号，或不输入数字来退出）`;
    return str;
}

export class StandardCharacter extends Character {
    override reportAction(a: ActionReportArguments): HistoryEntry {
        switch (a.type) {
        case ActionReportType.RunTowards:
            return NH.SP('action', this.agent, N.V('奔'), N.COM('向那里'));
        case ActionReportType.WalkTowards:
            return NH.SP('action', this.agent, N.V('走'), N.COM('向那里'));
        case ActionReportType.TurnOnOff:
        case ActionReportType.OpenClose:
            return NH.SVO('action', this.agent, 
                N.V(a.state ? '打开' : '关上').perfective(), a.object!);
        case ActionReportType.RunIntoObject:
            return NH.SP('action', this.agent, '奔向', a.zone!.name);
        case ActionReportType.WalkIntoObject:
            return NH.SP('action', this.agent, '走向', a.zone!.name);
        case ActionReportType.PickUpObject:
            return NH.SVO('action', this.agent, '拿起', a.object!);
        case ActionReportType.HoldUpObject:
            return NH.SVO('action', this.agent, '搬起', a.object!);
        case ActionReportType.DropObject:
            return NH.SP('action', this.agent, 
                N.AUX_V('把'), N.O(a.object!), N.V('放在了'), N.COM('地上'));
        case ActionReportType.PutInContainer:
            return NH.SP('action', this.agent, 
                N.AUX_V('把'), N.O(a.object!), N.V('放到了'), 
                N.COM(a.container!, 
                    a.container!.containerType == ContainerType.Surface 
                    ? '上面' : '里面'));
        case ActionReportType.TouchObject:
            return NH.SVO('action', this.agent, N.V('摸').perfective(), a.object!);
        case ActionReportType.ShakeObject:
            return NH.SVO('action', this.agent, N.V('晃').perfective(), a.object!);
        case ActionReportType.LockUnlockObject:
            return NH.SP('action', this.agent, 
                ...(a.instrument ? [N.ADV('用', N.IO(a.instrument))] : []), 
                N.V(a.state ? '锁上' : '解锁').perfective(), N.O(a.object!));
        case ActionReportType.WriteSomething:
            return NH.SP('action', this.agent, 
                N.ADV('用', N.IO(a.instrument!), '在', N.IO(a.object!), '上'), 
                N.V('写了些什么'));
        case ActionReportType.EraseSomething:
            return NH.SP('action', this.agent, 
                N.ADV('用', N.IO(a.instrument!)), 
                N.V('擦掉').perfective(), N.O(a.object!), '上的文字'); 
        case ActionReportType.HeardNothingSpecial:
            return NH.SP('meta', this.agent, '没有听到什么特别的声音');
        case ActionReportType.SmelledNothingSpecial:
            return NH.SP('meta', this.agent, '没有闻到什么特别的声音');
        case ActionReportType.FeltNothingSpecial:
        case ActionReportType.LockabilityInfo:
        case ActionReportType.UnLockabilityInfo:
        default:
            return U.metaText(this.agent, 
                `[unhandled RoutineAction: ${ActionReportType[a.type]}]`);
        }
    }

    protected actions: AVerb[] = [
        new VerbSpecification(
           /^(?<r1>跑步|跑|走)?(去|向|往)?((?<d1>东|西|南|北|东南|西南|东北|西北)边?|楼?(?<d2>上|下)(去|楼|面))(?<r2>跑步|跑|走)?$/)
           .stringParam('dir').source('d1', 'd2')
           .booleanParam('run').source('r1', 'r2')
           .link(() => this.agent.goDirection, (args) => 
               [DirectionNames.indexOf(args.str.dir), args.bool.run] as const),
        new VerbSpecification(
            /^(?<run>快速?|跑)?(出去?|回去|离开|逃(走|跑|脱|离|出)?)(房间|这里)?$/)
            .booleanParam('run')
            .link(() => this.agent.escape, (args) => [args.bool.run] as const),
        new VerbSpecification(
            /^(?<run>奔?跑|快速)?(走?进|走?回到?|出)(?<target>.+)$/)
            .booleanParam('run')
            .singleObjParam('target', 'object', '可以走进的东西').tangibleOnly()
            .link(() => this.agent.enterObj, (args) => 
                [args.single.target, args.bool.run] as const),
        new VerbSpecification(
            /^(看|观察|检查)(房间|周围|四周)?$/)
            .do(() => this.describeZone()),
        new VerbSpecification(
            /^(看|观察|检查)(?<obj>.+)$/)
            .singleObjParam('obj')  // single for now!
            .link(() => this.agent.describeObj, (args) => [args.single.obj]),

        new VerbSpecification(
            /^等(待|候)?((?<h>\d+(\.\d+)?)小?时)?((?<m>\d+(\.\d+)?)分钟?)?((?<s>\d+(\.\d+)?)秒)?$/)
            .stringParam('h').stringParam('m').stringParam('s')
            .do((args, self) => {
                let hr  = parseNumber(args.str.h ?? '0'),
                    min = parseNumber(args.str.m ?? '0'),
                    sec = parseNumber(args.str.s ?? '0');
                Debug.assert(!isNaN(hr) && !isNaN(min) && !isNaN(sec));
                // ADV_TODO
                if (!args.str.h && !args.str.m && !args.str.s)
                    return self.wait(10);
                return self.wait(hr * 3600 + min * 60 + sec);
            }),
        new VerbSpecification(
            /^(扔下|放下?|丢下?)(?<x>.+)$|^把(?<y>.+)(扔下|放下?|丢下?)$/)
            .multiObjParam('objs', 'object').source('x', 'y')
            .allowAll()
            .linkForEach('objs', 
                () => this.agent.drop, (x) => [x]),
        new VerbSpecification(
            /^((?<s1>开启|打开|开)|关闭|关上|关)(?<x>.+)$|^把(?<y>.+)((?<s2>打开)|关上)$/)
            .multiObjParam('objs', undefined, '可以开关的东西')
            .source('x', 'y').tangibleOnly()
            .condition((x) => x.isSwitch || x.isOpenable)
            .condition(
                (x, args) => (x.isSwitch && (x.switchState != args.bool.state)) 
                    || (x.isOpenable && (x.openState != args.bool.state)), 
                (obj, _, args) => this.reportFailState(
                    RoutineResult.ObjectAlreadyOpenedClosed(
                        {object: obj, state: args.bool.state}))?.submitMomentary())
            .booleanParam('state').source('s1', 's2')
            .doForEach('objs', (x, self, args) => x.isSwitch 
                ? self.agent.turnOnOff.execDirect(self.agent, x, args.bool.state)
                : self.agent.openClose.execDirect(self.agent, x, args.bool.state)),
        new VerbSpecification(
            /^把?(?<objs>.+)(放(?:在|进|到|上|回)?|拿(进|到|上)|挂(在|到|上|回))(?<cont>.+?)((上|里)面?)?$/)
            .singleObjParam('cont', 'container', '容器').tangibleOnly()
            .multiObjParam('objs', 'object', '事物').tangibleOnly()
            .policy({yieldSubobjectOfVisited: false})
            .linkForEach('objs', 
                () => this.agent.putObjIn,
                (obj, args) => [obj, args.single.cont]),
        new VerbSpecification(
            /^(拿|取|捉|抓|搬|抬)(出|走)?(?<x>.+)$|^把(?<y>.+)(拿|取|捉|抓|搬|抬)(出|走)?$/)
            .multiObjParam('objs', 'object').source('x', 'y').tangibleOnly()
            .linkForEach('objs', () => this.agent.takeObj, (x) => [x]),
        // ADV_TODO: 从。。。拿。。。
        new VerbSpecification(
            /^(按(一下|下)?|摁)(?<objs>.+)$/)
            .multiObjParam('objs', 'object').tangibleOnly()
            .linkForEach('objs', () => this.agent.press, (x) => [x]),
        new VerbSpecification(
            /^(推(一下)?)(?<objs>.+)$/)
            .multiObjParam('objs', 'object').tangibleOnly()
            .linkForEach('objs', () => this.agent.push, (x) => [x]),
        new VerbSpecification(
            /^(拉(一下)?|拔掉?)(?<objs>.+)$/)
            .multiObjParam('objs', 'object').tangibleOnly()
            .linkForEach('objs', () => this.agent.pull, (x) => [x]),
        new VerbSpecification(
            /^(状态|@)$/)
            .do(function* (_, self) { self.showStats() }),
        new VerbSpecification(
            /^(摇晃?|摇?晃)(?<objs>.+)$/)
            .multiObjParam('objs', 'object').tangibleOnly()
            .linkForEach('objs', () => this.agent.shake, (x) => [x]),
        new VerbSpecification(
            /^(触?摸|触碰)(?<objs>.+)$/)
            .multiObjParam('objs', 'object').tangibleOnly()
            .linkForEach('objs', () => this.agent.touch, (x) => [x]),
        new VerbSpecification(
            /^(闻)$/)
            .link(() => this.agent.smell, () => []),
        new VerbSpecification(
            /^(闻)(?<obj>.+)$/)
            .singleObjParam('obj', 'object')
            .link(() => this.agent.smellAt, (args) => [args.single.obj]),
        new VerbSpecification(
            /^(聆?听)$/)
            .link(() => this.agent.listen, () => []),
        new VerbSpecification(
            /^(聆?听)(?<obj>.+)$/)
            .singleObjParam('obj', 'object')
            .link(() => this.agent.listenTo, (args) => [args.single.obj]),
        new VerbSpecification(
            /^(用(?<key>.+))?(解锁|(?<open>开启?|打开)|(?<state>锁上?))(?<target>.+)$/)
            .singleObjParam('key', 'instrument').optional().tangibleOnly()
            .singleObjParam('target', 'object').tangibleOnly()
            .booleanParam('state', 'state')
            .booleanParam('open')
            .checkParams(() => this.agent.lockUnlock)
            .do(function* (args, self) {
                let obj = args.single.target;
                yield* self.agent.lockUnlock.execDirect(self.agent, 
                    obj, args.bool.state, args.single.key ?? null);
                if (!obj.isLocked && args.bool.open)
                    yield* self.agent.openClose.execDirect(self.agent, obj, true);
            }),
        new VerbSpecification(
            /^(用(?<instr>.+?))?(在(?<target>.+?)上面?)?写字?(：?(?<what>.+))?$/)
            .singleObjParam('instr', 'instrument', '书写工具')
            .tangibleOnly().defaultsTo('single')
            .singleObjParam('target', 'object', '书写对象')
            .tangibleOnly().defaultsTo('single')
            .stringParam('what').optional()
            .checkParams(() => this.agent.write)
            .do(function* (args, self) {
                let text = args.str.what ?? '';
                if (text == '') {
                    let res = 
                        yield World.schedule.requireGlobalInput('（输入要写的内容：）');
                    text = res.userInput;
                    if (text == '') return;
                }
                yield* self.agent.write.execDirect(self.agent, 
                    args.single.target, args.single.instr, text);
            }),
        new VerbSpecification(
            /^(用(?<instr>.+?))?擦除?(?<target>.+)$/)
            .singleObjParam('instr', 'instrument', '擦除工具').optional().tangibleOnly()
            .condition((x) => x.writing.isEraser)
            .multiObjParam('target', 'object', '书写对象').tangibleOnly()
            .condition((x) => x.writing.maxLength > 0)
            .linkForEach('target', 
                () => this.agent.erase, 
                (obj, args) => [obj, args.single.instr]),
    ];
}

export class Interpreter extends StandardCharacter {
    override reportFailState(r: RoutineResult) {
        console.log('failState:', RoutineResultType[r.type]);
        switch (r.type) {
        case RoutineResultType.CantDoWhileHoldingItem:
            return U.meta(this.agent, N.SP(this.agent, '必须把正在搬着的', this.agent.holdingItem!, '放下来，才能完成这个动作'));
        case RoutineResultType.NoStrength:
            return U.thought(this.agent, N.SP(this.agent, '已经没有力气了'));
        case RoutineResultType.NotEnoughStrength:
            return U.thought(this.agent, N.SP(this.agent, N.P('已经没有那么多力气了')));
        case RoutineResultType.NoPassage:
            return U.metaText(this.agent, '那里没有路。');
        case RoutineResultType.CantEscape:
            return U.metaText(this.agent, '[当前环境下，“出去”或“回去”不是一个清晰的指令]');
        case RoutineResultType.ObjectNotSwitch:
        case RoutineResultType.ObjectNotOpenable:
            return U.thought(this.agent, N.SP(this.agent, N.V('看不出'), N.O(r.object!), '怎么能够开关'));
        case RoutineResultType.ObjectLocked:
            return U.thought(this.agent, N.SP(r.object!, `紧紧锁着`));
        case RoutineResultType.ObjectAlreadyOnOff:
        case RoutineResultType.ObjectAlreadyOpenedClosed:
            return U.thought(this.agent, N.SP(r.object!, `已经是${r.state ? '开': '关'}着的了`));
        case RoutineResultType.ObjectNotEnterable:
            return U.meta(this.agent, N.SP(this.agent, '没法进入那里'));
        case RoutineResultType.ObjectNotTakable:
            return U.meta(this.agent, N.SP(this.agent, '拿不起来', N.O(r.object!)));
        case RoutineResultType.YouAlreadyHaveThis:
            return U.meta(this.agent, N.SVO(this.agent, '已经带着', r.object!, '了'));
        case RoutineResultType.YouDontHaveThis:
            return U.meta(this.agent, N.SVO(this.agent, '并没有带着', r.object!));
        case RoutineResultType.ObjectAlrealyInContainer:
            return U.meta(this.agent, N.SVO(r.object!, '已经在', r.container!, '里了'));
        case RoutineResultType.ObjectNotContainer:
            return U.meta(this.agent, N.SVO(r.object!, '放不下东西'));
        case RoutineResultType.CantPutObjectInItself:
            return U.meta(this.agent, ['这种行为在四维空间中也许很容易做到']);
        case RoutineResultType.ObjectAlreadyLockedUnlocked:
            return U.thought(this.agent, N.SVO(r.object!, r.object!.isLocked ? '已经锁上了' : '并没有锁上'));
        case RoutineResultType.CantLockUnlockObject:
            return U.meta(this.agent, N.SP(r.object!, `不是一个可${r.state ? '上锁' : '解锁'}的东西`));
        case RoutineResultType.ObjectNotWritable:
            return U.meta(this.agent, N.SP(r.object!, `不是一个能在上面写字的对象`));
        case RoutineResultType.ObjectNotWritingInstrument:
            return U.meta(this.agent, N.SP(r.object!, `并不是能写字的工具`));
        case RoutineResultType.ObjectNotEraser:
            return U.meta(this.agent, N.SP(r.object!, `并不是能擦掉文字的工具`));
        case RoutineResultType.CantDoWhileNotOpen:
            return U.meta(this.agent, N.SP(this.agent, '进不去，因为门没有打开'));
        case RoutineResultType.InventoryFull:
            return U.thought(this.agent, ['你的身上放不下那么多东西']);
        case RoutineResultType.OpeningTooNarrow:
            return U.thought(this.agent, N.SP(r.object!, `的开口太窄，你的手伸不进去`));
        case RoutineResultType.ContainerTooFull:
            return U.thought(this.agent, N.SP(r.container!, `${r.container!.containerType == ContainerType.Surface ? '上面' : '里'}剩余的空间放不下`, N.O(r.object!)));
        case RoutineResultType.ObjectLargerThanMouthPut:
            return U.thought(this.agent, N.SP(r.object!, `比`, r.container!, `的口更大，没法放进去`));
        case RoutineResultType.ObjectLargerThanMouthTake:
            return U.thought(this.agent, [`由于太大了，`, r.object!, `卡在`, r.container!, `的口上，没法拿出来`]);
        case RoutineResultType.NoWritingToErase:
        case RoutineResultType.ObjectNoWriting:
            return U.thought(this.agent, ['上面什么也没有写']);
        case RoutineResultType.ObjectNotShakable:
            return U.thought(this.agent, N.SVO(this.agent, '晃不动', r.object!));
        case RoutineResultType.NoWritingSpace:
            return U.thought(this.agent, N.SP(r.object!, `上写不下更多内容了`));
        case RoutineResultType.KeyNeeded:
            return U.thought(this.agent, N.SP(r.object!, `需要钥匙才能${r.state ? '上锁' : '解锁'}`));
        case RoutineResultType.IncorrectKey:
            return U.thought(this.agent, N.SP(r.object!, `不是合适的钥匙`));
        case RoutineResultType.NotUseful:
            return U.metaText(this.agent, `这没有什么用处。`);
        case RoutineResultType.Ok:
        case RoutineResultType.Continue:
        case RoutineResultType.ContinueSilent:
        case RoutineResultType.Interrupted:
        case RoutineResultType.CustomError:
            return null;
        case RoutineResultType.Bug:
        default:
            return super.reportFailState(r);
        }
    }

    override config: CommandConfig = {
        character: this,
        defaultRange: this.defaultConfig.defaultRange,
        notFoundMsg: (orig, name) => U.metaText(this.agent, `[你没有找到任何${name ? '这样的' + name : orig}]`).submitMomentary(),
        defaultsToMsg: (objs, name) => U.metaText(this.agent, `[默认${name}为：${objs.map((x) => x.name.value).join(', ')}]`).submitMomentary(),
        conditionNotMetMsg: (obj, name) => U.metaText(this.agent, `[${obj.name.value}不是一个${name ? name : '合适的对象'}]`).submitMomentary(),
        reportError: (err) => {
            let msg = `[未知错误：${err}]`;
            if (err instanceof NLPError) {
                if (err.message == 'syntax')
                    msg = `[错误：无法解析名词短语“${err.expr}”：请尝试换一种说法]`;
                else if (err.message == 'logic')
                    msg =  `[错误：无法解析名词短语“${err.expr}”：逻辑问题]`;
                else if (err.message == 'prohibited')
                    msg = err.detail == 'all' 
                        ? `[错误：名词短语“${err.expr}”过于宽泛]` 
                        : `[错误：名词短语“${err.expr}”似乎想表达多个事物]`;
                else if (err.message == 'unclear')
                    msg = `[错误：代词“${err.expr}”指代不清，请尝试写出具体对象]` ;
            }
            U.metaText(this.agent, msg).submitMomentary();
        },
    };

    override *describeZone(): ScheduledRoutine {
        let zone = this.agent.parentZone;
        let description = zone.description(zone, this.agent);
        U.metaText(this.agent, `*${zone.name}*  `).markGroup('zone').submitMomentary();
        U.meta(this.agent, description).markGroup('zone').submitMomentary();

        const objs: AObject[] = [];
        let hasObj = false;
        for (const obj of zone.extendedObjects())
            if (obj.shortDescription != null) {
                const d = obj.shortDescription(obj, this.agent);
                U.meta(this.agent, d).markGroup('zone').submitMomentary();
                hasObj = true;
            } else if (obj.showInDescription)
                objs.push(obj);

        for (const obj of objs) {
            U.meta(this.agent, N.SVO('这里', '还有', Signifier.forceIndefinite(obj)))
                .markGroup('therearealso').submitMomentary();
        }

        return yield* RoutineUtility.requireTime(2, this);
    }

    override *describeObject(objs: AObject[]): ScheduledRoutine {
        const obj = objs[0];

        // description, or "nondescript" clause. if contents can be seen or it's openable 
        // or it's a writing medium, skip the latter.
        const read = obj.writing.text.length > 0 || obj.writing.isStandardMedium;
        
        let desc: SentenceContent | null = null;
        if (obj.description != null)
            desc = obj.description(obj, this.agent);
        if ((!obj.canSeeContents && !obj.isOpenable && !read) || desc != null) {
            desc = desc ?? N.text('你没有看到任何特殊之处。');
            U.meta(this.agent, desc).submitMomentary();
            
            if (!(yield* this.autoPassTime(1)))
                return RoutineResult.Interrupted({}, true);
        }

        // describe parts
        for (const part of obj.parts)
            if (part.shortDescription != null) {
                const d = part.shortDescription(part, this.agent);
                U.meta(this.agent, d).submitMomentary();
            }

        // describe writing
        if (read) yield* this.agent.read.execDirect(this.agent, obj);

        // open state
        if (obj.isOpenable) U.meta(this.agent, 
            [N.S(obj), N.P(N.V(`${obj.openState ? '敞开' : '关'}着`))]).submitMomentary();
        
        // describe container content
        if (obj.canSeeContents) {
            if (obj.contents.size > 0) {
                let [x, v] = obj.containerType == ContainerType.Surface 
                    ? ['上面', '放着'] : ['里面', '有'];
                
                for (let subobj of obj.contents) {
                    U.meta(this.agent, N.SVO(obj, N.V(x + v).stative(), Signifier.forceIndefinite(subobj))).markGroup('content').submitMomentary();
                }
                if (!(yield* this.autoPassTime(1)))
                    return RoutineResult.Interrupted({}, true);
            } else {
                if (obj.containerType == ContainerType.Surface)
                    U.meta(this.agent, 
                        [N.S(obj), N.P('上面没有放任何东西')]).submitMomentary();
                else U.meta(this.agent, 
                        [N.S(obj), N.P('里面没有任何东西')]).submitMomentary();
            }
        }
        return RoutineResult.Continue();
    }

    override *readObject(obj: AObject): ScheduledRoutine {
        U.metaText(this.agent, '你读到：').submitMomentary();
        for (let ch of obj.writing.text) {
            U.metaText(this.agent, `$${ch}$`).submitMomentary();

            let t = wcwidth(ch) > 1 ? 0.15 : 0.05; // rough approx. for Chinese + English
            if (!(yield* this.autoPassTime(t)))
                return RoutineResult.Interrupted({}, true);
        }
        return RoutineResult.Continue();
    }

    override *onInterrupt(level: number): TypedScheduledProcess<boolean> {
        if (level < this.ignoreLevel) return false;
        let result = yield World.schedule.requireGlobalInput('（输入Y忽略，输入其他则中断）');
        return result.userInput.toLowerCase() != 'y';
    }

    override *disambiguateResults(expression: string, candidates: AObject[]): TypedScheduledProcess<AObject | null> {
        // ADV_TODO: unclearObjects
        Debug.assert(candidates.length > 1);
        let resp = yield World.schedule.requireGlobalInput(
            disamb(this.agent, expression, candidates));
        let input = Number.parseInt(resp.userInput);
        if (isNaN(input) || input < 0 || input >= candidates.length) {
            return null;
        }
        return candidates[input];
    }

    override *wait(time: number): ScheduledProcess {
        // ADV_TODO: check if there are any timing devices present, etc.
        let target = World.schedule.absoluteTime + time;
        while (true) {
            U.thought(this.agent, ['时间流逝']).submitMomentary();
            let result = yield World.schedule.requireTime(
                target - World.schedule.absoluteTime,);
            if (result.success) return true;
            if (yield* this.onInterrupt(result.interrupt!.severity)) return false;
        }
    }

    override showStats(): void {
        // ADV_TODO: force article here
        for (let obj of this.agent.inventory) U.thought(this.agent, 
            N.SVO(this.agent, '带着', Signifier.forceIndefinite(obj))).submitMomentary();
        if (this.agent.inventory.size == 0) U.thought(this.agent, 
            N.SP(this.agent, '什么都没带')).submitMomentary();
        if (this.agent.holdingItem != null) U.thought(this.agent, 
            N.SVO(this.agent, '搬着', Signifier.forceIndefinite(this.agent.holdingItem))).submitMomentary();
        // ADV_TODO: verbal representation of strength?
        U.metaText(this.agent, `体力：${(this.agent.strength * 100).toFixed(1)}%\n负重：${this.agent.totalLoadMass.toFixed(3)}kg\n负载体积：${this.agent.inventoryTotalSize}cm^3`).submitMomentary();
    }
}